home *** CD-ROM | disk | FTP | other *** search
-
- /*
- File: CubicLibrary.c
-
- Contains: graphics libraries - cubic library
-
- Written by: Hugo Ayala
-
- Copyright: © 1995 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <2> 4/7/95 jtd changed 'fract' to 'Fract'
- <1> 1/9/95 JD First checked in.
- */
-
- #include "GraphicsLibraries.h"
-
- typedef struct { /* this structure contains the cached cubic coefficients */
- Fixed ax, ay;
- Fixed bx, by;
- Fixed cx, cy;
- Fixed dx, dy;
- } xCubic;
-
- typedef struct { /* this structure is just for a gxPath */
- long contours;
- long count;
- long flags;
- gxPoint data[ 32 ];
- } smallPath;
-
-
- /* macros to calculate the inner products */
-
- #define XCube(xc,u) (FractMultiply(FractMultiply(FractMultiply((xc)->ax,(u))+(xc)->bx,(u))+(xc)->cx,(u))+(xc)->dx)
- #define YCube(xc,u) (FractMultiply(FractMultiply(FractMultiply((xc)->ay,(u))+(xc)->by,(u))+(xc)->cy,(u))+(xc)->dy)
-
- #define XCubePrime(xc,u) (FractMultiply(FractMultiply((3*(xc)->ax),(u))+(2*(xc)->bx),(u))+(xc)->cx)
- #define YCubePrime(xc,u) (FractMultiply(FractMultiply((3*(xc)->ay),(u))+(2*(xc)->by),(u))+(xc)->cy)
-
-
- /* This routine calculates the number of cubics that would be needed to draw a with no more than a pixel error. */
- static long xCountQuadratics( const cubic *cube )
- {
- Fixed ax = -cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x; /* first get the a vector components */
- Fixed ay = -cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y;
- short temp;
- long count;
-
- if( ax < 0 ) /* make sure that they are positive */
- ax = -ax;
- if( ay < 0 )
- ay = -ay;
- ax = ( ay < ax ) ? ax : ay; /* pick the max one */
-
- temp = ( FixedDivide( ax, ff( 20 ) ) + 0xFFFF ) >> 16; /* we now divide by twenty and take the ceiling */
-
- /* NOTE: if you want the tolerance to be .5 then */
- /* divide ax by 10, .25 -> 5, etc */
-
- /* this is a crude but fast and effective way of taking the cube root of */
- /* 'temp' which is between 0 and 27000 */
-
- if( temp <= 4096 ) {
- if( temp <= 512 ) {
- if( temp <= 64 ) {
- if( temp <= 8 ) {
- if( temp <= 1 )
- count = 1;
- else
- count = 2;
- } else {
- if( temp <= 27 )
- count = 3;
- else
- count = 4;
- }
- } else {
- if( temp <= 216 ) {
- if( temp <= 125 )
- count = 5;
- else
- count = 6;
- } else {
- if( temp <= 343 )
- count = 7;
- else
- count = 8;
- }
- }
- } else {
- if( temp <= 1728 ) {
- if( temp <= 1000 ) {
- if( temp <= 729 )
- count = 9;
- else
- count = 10;
- } else {
- if( temp <= 1331 )
- count = 11;
- else
- count = 12;
- }
- } else {
- if( temp <= 2744 ) {
- if( temp <= 2197 )
- count = 13;
- else
- count = 14;
- } else {
- if( temp <= 3375 )
- count = 15;
- else
- count = 16;
- }
- }
- }
- } else {
- if( temp <= 13824 ) {
- if( temp <= 8000 ) {
- if( temp <= 5832 ) {
- if( temp <= 4913 )
- count = 17;
- else
- count = 18;
- } else {
- if( temp <= 6859 )
- count = 19;
- else
- count = 20;
- }
- } else {
- if( temp <= 10648 ) {
- if( temp <= 9261 )
- count = 21;
- else
- count = 22;
- } else {
- if( temp <= 12167 )
- count = 23;
- else
- count = 24;
- }
- }
- } else {
- if( temp <= 21952 ) {
- if( temp <= 17576 ) {
- if( temp <= 15625 )
- count = 25;
- else
- count = 26;
- } else {
- if( temp <= 19683 )
- count = 27;
- else
- count = 28;
- }
- } else {
- if( temp <= 27000 ) {
- if( temp <= 24389 )
- count = 29;
- else
- count = 30;
- } else /* because our gxPath can only contain 32 -2 points we stop here */
- count = 30;
- }
- }
- }
- return count;
- }
-
-
- /* This routine is where the cuadratic points get computed. Note that this
- routine never fills in the last gxPoint in the code. It also assumes that the first gxPoint has been moved in by the caller.
-
- cubic -> a pointer to the cubic
- count -> the number of points other than the two end ones that we need to generate
- storage -> a place to put the points that are generated
- */
- static gxPoint *ComputePoints( const cubic *cube, long count, gxPoint *storage )
- {
- Fixed *ptr = &storage->x;
-
- if( 0 < count )
- { xCubic x;
- Fract n = FractDivide( 1, count ); /* LongInt / LongInt -> frac */
- Fract u = n;
- Fixed tempx1 = cube->a.x >> 1;
- Fixed tempy1 = cube->a.y >> 1;
- Fixed tempx2, tempy2;
-
- /* we compute the coefficients for this cubic -- for efficient computation later */
-
- x.ax = -cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x;
- x.ay = -cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y;
- x.bx = 3 * cube->a.x - 6 * cube->b.x + 3 * cube->c.x;
- x.by = 3 * cube->a.y - 6 * cube->b.y + 3 * cube->c.y;
- x.cx = -3 * cube->a.x + 3 * cube->b.x;
- x.cy = -3 * cube->a.y + 3 * cube->b.y;
- x.dx = cube->a.x;
- x.dy = cube->a.y;
- tempx2 = FractMultiply( x.cx, n ) >> 2;
- tempy2 = FractMultiply( x.cy, n ) >> 2;
-
- for( ; 0 < count; --count )
- { Fixed ntempx1 = XCube( &x, u ) >> 1; /* compute the next gxPoint sequence */
- Fixed ntempy1 = YCube( &x, u ) >> 1;
- Fixed ntempx2 = FractMultiply( XCubePrime( &x, u ), n ) >> 2;
- Fixed ntempy2 = FractMultiply( YCubePrime( &x, u ), n ) >> 2;
-
- *ptr++ = tempx1 + tempx2 + ntempx1 - ntempx2; /* store the gxPoint */
- *ptr++ = tempy1 + tempy2 + ntempy1 - ntempy2;
- tempx1 = ntempx1;
- tempx2 = ntempx2;
- tempy1 = ntempy1;
- tempy2 = ntempy2;
- u += n;
- }
- *ptr++ = cube->d.x; /* move in the last gxPoint of the cubic */
- *ptr++ = cube->d.y;
- }
- return (gxPoint *) ptr;
- }
-
-
- /* This routine fills in a data structure for a gxPath with the information of a cubic.
- pathptr -> a pointer to the gxPath
- cube -> the cubic
- count -> how many points to use
- */
- static void CubicPath( smallPath *pathptr, const cubic *cube, const long count )
- {
- gxPoint *ptr;
-
- pathptr->contours = 1;
- pathptr->count = count + 2;
- pathptr->flags = ~((unsigned long) 0x80000000 >> count + 1) & 0x7FFFFFFF;
-
- ptr = pathptr->data;
- *ptr++ = cube->a;
- ComputePoints( cube, count, ptr );
- }
-
-
- /* This routine draws a cubic with the given fill */
- void DrawCubic( const cubic *cube, gxShapeFill theFill )
- {
- gxShape sh = NewCubic( cube );
-
- if (theFill != GXGetShapeFill(sh))
- GXSetShapeFill(sh, theFill);
- GXDrawShape( sh );
- GXDisposeShape( sh );
- }
-
-
- /* This routine sets the points inside of a gxPath to be those of the given cubic */
- void SetCubic( gxShape dest, const cubic *cube )
- {
- smallPath pathrec;
-
- CubicPath( &pathrec, cube, xCountQuadratics( cube ) );
- GXSetPaths( dest, (gxPaths *) &pathrec );
- }
-
-
- /* This routine makes a new cubic that has a tolerance of one pixel. */
- gxShape NewCubic( const cubic *cube )
- {
- smallPath pathrec;
-
- CubicPath( &pathrec, cube, xCountQuadratics( cube ) );
- return GXNewPaths((gxPaths *) &pathrec );
- }
-
-
- /* This routine is the same as above except that it has an optional parameter for determining how many points to
- include in a gxPath. The number determines the number of points 'off' the gxCurve which are needed.
-
- If you use this routine you should link it in with another which determines the number of points to be used.
- Here is an example that depends on a global variable 'gerror' of type extended. Also, see the 'optimized'
- example for 'xCountQuadratics' above.
- */
- #ifdef NewCubic2Defined
- #include <math.h>
-
- #ifdef THINK_C
- #define extended long double
- #define power pow
- #endif
-
- #define FixedToExtended(a) ((extended)(a) / fixed1)
-
- extended gerror = 1.0;
-
- static long CountQuadratics( const cubic *cube )
- {
- extended ax = FixedToExtended( - cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x );
- extended ay = FixedToExtended( - cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y );
- extended a = sqrt( ax * ax + ay * ay );
- extended n = power( ( a / ( 20.0 * gerror ) ), 1.0 / 3.0 );
- long count = ceil( n );
-
- if( count <= 0 )
- count += 1;
- return count;
- }
-
- gxShape NewCubic2( const cubic *cube, const long count );
- gxShape NewCubic2( const cubic *cube, const long count )
- {
- smallPath pathrec;
-
- CubicPath( &pathrec, cube, ( count <= 0 ) ? CountQuadratics( cube ) : count );
- return GXNewPaths((gxPaths *) &pathrec );
- }
- #ifdef THINK_C
- #undef extended
- #endif
-
- #undef FixedToExtended
- #endif
-